package com.higgins.lawapp.server;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;

import com.higgins.lawapp.client.settings.dataItemModel.DataItemDTO;
import com.higgins.lawapp.client.settings.dataItemModel.DataItemInstanceDTO;
import com.higgins.lawapp.client.settings.dataItemModel.DataItemLevelDTO;
import com.higgins.lawapp.client.settings.dataItemModel.DataItemSourceDTO;
import com.higgins.lawapp.client.settings.dataModel.DataSourceDTO;
import com.higgins.lawapp.client.settings.dataModel.DataSourceLevelDTO;
import com.higgins.lawapp.client.settings.dataModel.DataSourceObjectDTO;
import com.higgins.lawapp.server.dataItemModel.DataItem;
import com.higgins.lawapp.server.dataItemModel.DataItemContainer;
import com.higgins.lawapp.server.dataItemModel.DataItemInstance;
import com.higgins.lawapp.server.dataItemModel.DataItemLevel;
import com.higgins.lawapp.server.dataItemModel.DataItemSource;
import com.higgins.lawapp.server.dataModel.DataSource;
import com.higgins.lawapp.server.dataModel.DataSourceLevel;
import com.higgins.lawapp.server.dataModel.DataSourceObject;

public class DataCollectionEngine {
	private DataCollectionStoreEngine dataCollectionStoreEngine = new DataCollectionStoreEngine();
	private InternetManager internetManager = new InternetManager();
	private String dataSourceLevelCollected = null;
	private boolean testMode = false;
	private int collectionCount = 0;
	private int maxCollection = 20;
	
	public void clearVariablesForNewRun()	{
		dataSourceLevelCollected = null;
		collectionCount = 0;
	}
	
	public void setTestMode(boolean testMode)	{
		this.testMode = testMode;
	}
	public boolean getTestModeL(){
		return testMode;
	}
	
	public void collectDataSource(DataSource dataSource)	{
		 collectDataSource(dataSource, null);
	}

	public void collectDataSource(DataSource dataSource, List<String> testFilenames)	{
		List<DataItem> dataItemsForPreviousLevel = null;
		String urlField = null;
		int levelCount=0;
		for (DataSourceLevel dataSourceLevel:dataSource.getDataSourceLevels())	{
			System.out.println("Starting on Level = " + dataSourceLevel.getDataSourceName());
			if (testMode || dataSourceLevelCollected==null || dataSourceLevelCollected.equals(dataSourceLevel.getDataSourceName())) 	{
				dataItemsForPreviousLevel = collectLevel(dataSourceLevel, dataItemsForPreviousLevel, urlField, levelCount, testFilenames);			
			}
			levelCount++;
		}	
	}

	public List<DataItem> collectLevel(DataSourceLevel dataSourceLevel, List<DataItem> dataItemsForPreviousLevel, String urlField, int levelCount)	{
		return collectLevel(dataSourceLevel, dataItemsForPreviousLevel, urlField, levelCount, null);
	}

	public List<DataItem> collectLevel(DataSourceLevel dataSourceLevel, List<DataItem> dataItemsForPreviousLevel, String urlField, 
			int levelCount, List<String> testFilenames)	{
		List<DataItem> newDataItemsForNextLevel = new ArrayList<DataItem>();
		try	{
			if (dataItemsForPreviousLevel!=null)	{							// LEVELS OTHER THAN LEVEL ONE
				if (dataSourceLevel.getDataSourceExecution())	{
					for (DataItem dataItem:dataItemsForPreviousLevel)	{
						if (collectionCount > maxCollection)
							throw new CollectionCountExceededException();
						if(!dataCollectionStoreEngine.retrieveInstanceDataItems(dataSourceLevel, newDataItemsForNextLevel, dataItem))
							collectInstance(dataSourceLevel, newDataItemsForNextLevel, dataItem, testFilenames);
					}
		
				}	else {
							retrieveNotCollectInstance(dataSourceLevel.getDataSourceName(), levelCount, newDataItemsForNextLevel);
							if (testFilenames!=null && testFilenames.size() > 0)
								testFilenames.remove(0);
		
				}
			}	else	{														// THE FIRST LEVEL!!!
				if (dataSourceLevel.getDataSourceExecution())	{
					if(!dataCollectionStoreEngine.retrieveInstanceDataItems(dataSourceLevel, newDataItemsForNextLevel, null))
						collectInstance(dataSourceLevel, newDataItemsForNextLevel, null, testFilenames);
	
				}	else	{
					retrieveNotCollectInstance(dataSourceLevel.getDataSourceName(), levelCount, newDataItemsForNextLevel);
					if (testFilenames!=null && testFilenames.size() > 0)
						testFilenames.remove(0);
				}
			}	
		} catch (CollectionCountExceededException e)	{
			
		}
		dataItemsForPreviousLevel = newDataItemsForNextLevel;
		return dataItemsForPreviousLevel;
	}
	
	public void collectInstance(DataSourceLevel dataSourceLevel, List<DataItem> newDataItemsForNextLevel, DataItem dataItem)	{
		collectInstance(dataSourceLevel, newDataItemsForNextLevel, dataItem, null);
	}
	
	public void collectInstance(DataSourceLevel dataSourceLevel, List<DataItem> newDataItemsForNextLevel, DataItem dataItem, 
			List<String> filenames)	{
		List<DataItem> dataItemListForInstance = null;
		try {
			if (useFilesInstead(filenames))	{
				dataItemListForInstance = internetManager.executeDataItemCollection(dataSourceLevel, getFirstUrl(dataItem), 
						getFirstConcat(dataItem), getFilename(filenames));
			}	else	{
				collectionCount++;
				System.out.println(internetManager.generateURLText(dataSourceLevel, dataItem));
				dataItemListForInstance = internetManager.executeDataItemCollection(dataSourceLevel, getFirstUrl(dataItem), 
						getFirstConcat(dataItem));
			}
			dataSourceLevelCollected = dataSourceLevel.getDataSourceName();
			addCollectionTimestamp(dataItem);
			storeDataItems(dataSourceLevel, createNewDataSourceLevel(dataSourceLevel), dataItemListForInstance, 
					 dataItem);
			
		} catch (NoDataSourceObjectsException e) {
			e.printStackTrace();
		} catch (ScreenScrapeFailedException e)	{
			e.printStackTrace();
		}
		
		delay(10, filenames);
		
		addToCollectionForNextPass(newDataItemsForNextLevel, dataItemListForInstance);		// Still do this for other instances? Doesn't seem right
	}
	
	private void addCollectionTimestamp(DataItem dataItem)	{
		dataCollectionStoreEngine.openConnection();
		dataCollectionStoreEngine.update(dataItem);
		dataCollectionStoreEngine.closeConnection();
	}
	
	private void storeDataItems(DataSourceLevel dataSourceLevel, DataItemContainer dataItemContainer, 
			List<DataItem> dataItemListForInstance, DataItem dataItem)	{
		List<DataItem> dataItems = new ArrayList<DataItem>();
		Iterator<DataItem> iterator = dataItemListForInstance.iterator();
		while(iterator.hasNext())	{
			DataItem dataItemtemp = iterator.next();
			dataItemtemp.setType("Instance");
			dataItems.add(dataItemtemp);
		}
		
		String sourceName = "Law Careers";		// Work on this.
		String levelName = dataSourceLevel.getDataSourceName();
		String instanceName = getFirstUrlName(dataSourceLevel, dataItem);
		List<String> titles = new ArrayList<String>();
		setDataItemTitles(titles, dataSourceLevel);
		
		dataItemContainer.setDataSource(sourceName);
		dataItemContainer.setDataLevel(levelName);
		dataItemContainer.setDataInstance(instanceName);
		dataItemContainer.setDataItems(dataItems);
		dataItemContainer.setDataItemTitles(titles);
		dataItemContainer.setCollectionTimestamp(new Date());
		dataItemContainer.setURL(InternetManager.generateURLText(dataSourceLevel, dataItem));
		
			
		dataCollectionStoreEngine.openConnection();
		dataCollectionStoreEngine.StoreDataItems(dataItemContainer);
		dataCollectionStoreEngine.closeConnection();
	}
	
	
	public void retrieveNotCollectInstance(String levelName, int levelCount, List<DataItem> newDataItemsForNextLevel)	{
		dataCollectionStoreEngine.openConnection();
		List<DataItemContainer> dataItemContainers = dataCollectionStoreEngine.retrieveLevelDataItems(levelName);
		
		for (DataItemContainer dataItemContainer:dataItemContainers)	{
			List<DataItem> dataItemListForInstance = dataItemContainer.getDataItems();
			addToCollectionForNextPass(newDataItemsForNextLevel, dataItemListForInstance);					
		}
		
		dataCollectionStoreEngine.closeConnection();
	}
	
	private DataItemContainer createNewDataSourceLevel(DataSourceLevel dataSourceLevel)	{
		DataItemContainer dataItemContainer = new DataItemContainer();
		List<DataSourceObject> dataSourceObjects = dataSourceLevel.getDataSourceObjects();
		Iterator<DataSourceObject> iterator = dataSourceObjects.iterator();
		List<String> dataItemTitles = new ArrayList<String>();
		while (iterator.hasNext())	{
			DataSourceObject dataSourceObject = iterator.next();
			if (dataSourceObject.getDataSourceType().equals("Field"))	{
				String fieldName = dataSourceObject.getDataSourceFieldName();
				dataItemTitles.add(fieldName);
			}
		}
		dataItemContainer.setDataItemTitles(dataItemTitles);
		return dataItemContainer;
	}
	
	private void setDataItemTitles(List<String> titles, DataSourceLevel dataSourceLevel)	{
		List<DataSourceObject> dataSourceObjects = dataSourceLevel.getDataSourceObjects();
		Iterator<DataSourceObject> iterator = dataSourceObjects.iterator();
		int count=0;
		while (iterator.hasNext())	{
			DataSourceObject dataSourceObject = iterator.next();
			if (dataSourceObject.getDataSourceType().equals("Field"))	{
				String fieldName = dataSourceObject.getDataSourceFieldName();
				switch(count)	{
				case 0:
					titles.add(fieldName);
					break;
				case 1:
					titles.add(fieldName);
					break;
				case 2:
					titles.add(fieldName);
					break;
				case 3:
					titles.add(fieldName);
					break;
				case 4:
					titles.add(fieldName);
					break;
				}
				count++;
			}
		}
	}
	
	
	private String getFirstUrlName(DataSourceLevel dataSourceLevel, DataItem dataItem)	{
		if (dataItem!=null)	
			return dataItem.getFirstName();	
		String firstUrl = "";
		List<DataSourceObject> dataSourceObjects = dataSourceLevel.getDataSourceObjects();
		if (dataSourceObjects!=null)	{
			Iterator<DataSourceObject> iterator = dataSourceObjects.iterator();
			while(iterator.hasNext())	{
				DataSourceObject dataSource = iterator.next();
				if (dataSource.getDataSourceType().equals("Field"))
					if (dataSource.getURL())
						firstUrl = dataSource.getDataSourceFieldName();
			}
		}
		return firstUrl;
	}
	
	private void delay(int delay, List<String> filenames)	{
		  try   {
			if (filenames==null)	{
				int maximumDelay= delay*1000;
				Random random = new Random();
				int randomDelay = random.nextInt(maximumDelay);
				int minimumDelay = (delay * 1000/2);
				System.out.println("Delay("+ (minimumDelay + randomDelay) + ")");
				System.out.println(" ");
				Thread.sleep(minimumDelay + randomDelay);  
			}
		  }	catch (InterruptedException ie)  {
			  String exception = ie.getMessage();
		  }
	}

	private String getFirstUrl(DataItem dataItem)	{
		if (dataItem!=null)	
			return dataItem.getFirstUrl();
		return null;
	}
	private Boolean getFirstConcat(DataItem dataItem)	{
		if (dataItem!=null)	
			return dataItem.getFirstConcat();
		return null;
	}
	private String getFilename(List<String> filenames)	{
		String filename = "";
		if (filenames!=null && filenames.size() > 0)	{
			filename = filenames.get(0);
			filenames.remove(0);
		}
		return filename;
	}
	private Boolean useFilesInstead(List<String> filenames)	{
		return filenames!=null;
	}	
	
	private void addToCollectionForNextPass(List<DataItem> newDataItemsForNextLevel, List<DataItem> dataItemListForInstance)	{
		Iterator<DataItem> iterator = dataItemListForInstance.iterator();
		while (iterator.hasNext()) {
			DataItem dataItem = iterator.next();
			newDataItemsForNextLevel.add(dataItem);
		}
	}
}
